package com.acxy.ants.core.config;

import com.acxy.ants.common.enums.ResponseCode;
import com.acxy.ants.common.kit.RequestKit;
import com.acxy.ants.core.Handler;
import com.acxy.ants.core.exception.SQLParamsException;
import com.acxy.ants.core.exception.TipException;
import com.acxy.ants.resful.render.Json;
import com.mysql.jdbc.MysqlDataTruncation;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
import com.sun.jdi.InvocationException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author MrShun
 * @version 1.0
 * @Date 2017-04-27
 */
final public class Handlers {

    private final List<Handler> handlerList = new ArrayList<>();

    private Constants constants;

    public Handlers add(Handler handler) {
        if (handler == null) {
            throw new IllegalArgumentException("handler can not be null");
        }
        handlerList.add(handler);
        return this;
    }

    /**
     * 循环执行链表
     * @return
     */
    public boolean execute(String target, HttpServletRequest request, HttpServletResponse response){
        boolean isHandle = true;
        for(Handler handler : handlerList){
            try {
                isHandle = handler.preHandle(target, request, response);
                if(!isHandle) return false;
            }catch (InvocationTargetException e){ //处理代理异常
                Throwable ex = e.getTargetException();
                ex.printStackTrace();
                errorWrite(request,  response, ex);
                return false;
            } catch (Exception e) { //处理Controller异常
                e.printStackTrace();
                errorWrite(request,  response, e);
                return false;
            }
        }
        return isHandle;
    }

    private void errorWrite(HttpServletRequest request, HttpServletResponse response, Throwable e){
        String requestType = request.getHeader("x-requested-with");
        Class<? extends Throwable> cls = e.getClass();
        if ("XMLHttpRequest".equals(requestType) || RequestKit.isApp(request)) {//ajax 或者原生app
            if(cls == TipException.class) //处理消息提示异常
                Json.writeJson(Json.exception(ResponseCode.ARGUMENTS_ERROR, e.getMessage()), response);
            else if(cls == SQLParamsException.class){ //处理数据库异常
                Class sqlClass = ((SQLParamsException)e).getSqlException().getClass();
                //数据外键约束异常
                if(sqlClass == MySQLIntegrityConstraintViolationException.class)
                    Json.writeJson(Json.exception(ResponseCode.RESTRIC_ERROR, "删除失败, 请先删除关联子数据!"), response);
                //数据字段过长异常
                else if(sqlClass == MysqlDataTruncation.class)
                    Json.writeJson(Json.exception(ResponseCode.COLUMN_LONG_ERROR, "某个数据字段, 内容超出!"), response);
            }else if(cls == NullPointerException.class)
                Json.writeJson(Json.exception(ResponseCode.NULL_POINT_ERROR), response);
            else if(cls == IllegalArgumentException.class)
                Json.writeJson(Json.exception(ResponseCode.ARGUMENTS_ERROR, e.getMessage()), response);
            else
                Json.writeJson(Json.exception(ResponseCode.UNKNOWN_ERROR, e.getMessage()), response);
        } else {
            try {
                if(cls == FileNotFoundException.class)
                    request.getRequestDispatcher(constants.getError404Page()).forward(request, response);
                else
                    request.getRequestDispatcher(constants.getError500Page()).forward(request, response);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public List<Handler> getHandlerList() {
        return handlerList;
    }

    public void setConstants(Constants constants){
        this.constants = constants;
    }
}